﻿// Original author contact info: Owen Emlen (owene_1998@yahoo.com)
// Note: other individuals may also have contributed to this code
// Project hosted on CodePlex.com as of 1/10/2009 at http://wpfimageviewer.codeplex.com
using System;
using System.Collections.ObjectModel;
using BrainTechLLC.ImageOperators;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;
using BrainTechLLC;
using CPPClassLibrary;
using DirectoryViewModels;
using ImageAppDataModels;
using ImageAppViewModels;
using System.IO;
using System.Collections.Generic;
using System.Text;
using BrainTechLLC.ThreadSafeObjects;
using System.Drawing;
using System.Windows.Media;
using System.Reflection;
using BinaryNorthwest;
using BrainTechLLC.FilterExtensions;
using System.Collections;


namespace WpfImageDuplicates
{
    public partial class Window1
    {
        ThreadSafeLookupOnDemand<Type, List<PropertyInfo>> _TypePropertyLookup = new ThreadSafeLookupOnDemand<Type, List<PropertyInfo>>();

        public bool HandleList<T>(object parent, CountClass count) where T : class
        {
            IList<T> efivm = parent as IList<T>;
            if (efivm != null)
            {
                for (int n = 0; n < efivm.Count; n++)
                {
                    Crawl(efivm[n], count);
                }
                return true;
            }
            return false;
        }

        public bool HandleObservable<T>(object parent, CountClass count) where T : class
        {
            ObservableCollection<T> ofivm = parent as ObservableCollection<T>;
            if (ofivm != null)
            {
                for (int n = 0; n < ofivm.Count; n++)
                {
                    Crawl(ofivm[n], count);
                }
                return true;
            }
            return false;
        }

        public bool HandleEnumerable<T>(object parent, CountClass count) where T : class
        {
            IEnumerable<T> enumfiym = parent as IEnumerable<T>;
            if (enumfiym != null)
            {
                foreach (var i in enumfiym)
                {
                    Crawl(i, count);
                }
                return true;
            }

            return false;
        }

        public void Crawl(object parent, CountClass count)
        {
            if (parent == null)
            {
                return;
            }

            //Type parentType = parent.GetType();
            //var v = from prop in parentType.GetProperties()
            //        where prop.CanRead && typeof(IEnumerable).IsAssignableFrom(prop.PropertyType)
            //        select prop;

            //foreach (var items in v)
            //{
            //    var obj = items.GetValue(parent, null);
            //    IEnumerable enumerable = obj as IEnumerable;
            //    if (enumerable != null)
            //    {
            //        int ct = 0;
            //        foreach (object o in enumerable)
            //        {
            //            ct++;
            //        }
            //        if (ct > 500)
            //        {
            //            Console.WriteLine(string.Format("{0} objects, Type {1} on {2}, Property {3}", ct, items.PropertyType.Name, parentType.Name, items.Name));
            //        }
            //    }
            //}

            FileImageViewModel fivm = parent as FileImageViewModel;
            FileImage fi = parent as FileImage;
            IFileImage ifi = parent as IFileImage;
            Bitmap bm = parent as Bitmap;
            ImageSource img = parent as ImageSource;
            byte[] bytes = parent as byte[];
            ThumbnailView vw = parent as ThumbnailView;
            FileImageCollection fiCollection = parent as FileImageCollection;

            if (bytes != null)
            {
                count.AddCount(bytes);
            }
            else if (vw != null)
            {
                count.AddCount(vw);
            }
            else if (fivm != null)
            {
                count.AddCount(fivm);
            }
            else if (fi != null)
            {
                count.AddCount(fi);
            }
            else if (ifi != null)
            {
                count.AddCount(ifi);
            }
            else if (bm != null)
            {
                count.AddCount(bm);
            }
            else if (img != null)
            {
                count.AddCount(img);
            }
            else if (fiCollection != null)
            {
                foreach (var fileImage in fiCollection)
                {
                    Crawl(fileImage, count);
                }
            }
            else
            {
                if (!HandleList<FileImageViewModel>(parent, count))
                {
                    if (!HandleObservable<FileImageViewModel>(parent, count))
                    {
                        if (!HandleEnumerable<FileImageViewModel>(parent, count))
                        {
                            if (!HandleList<ImageSource>(parent, count))
                            {
                                if (!HandleObservable<ImageSource>(parent, count))
                                {
                                    if (!HandleEnumerable<ImageSource>(parent, count))
                                    {
                                        if (!HandleList<Bitmap>(parent, count))
                                        {
                                            if (!HandleObservable<Bitmap>(parent, count))
                                            {
                                                if (!HandleEnumerable<Bitmap>(parent, count))
                                                {
                                                    if (!HandleList<FileImage>(parent, count))
                                                    {
                                                        if (!HandleObservable<FileImage>(parent, count))
                                                        {
                                                            if (!HandleEnumerable<FileImage>(parent, count))
                                                            {
                                                                if (!HandleList<IFileImage>(parent, count))
                                                                {
                                                                    if (!HandleObservable<IFileImage>(parent, count))
                                                                    {
                                                                        if (!HandleEnumerable<IFileImage>(parent, count))
                                                                        {
                                                                            if (!HandleEnumerable<ThumbnailView>(parent, count))
                                                                            {
                                                                                if (!HandleList<ThumbnailView>(parent, count))
                                                                                {
                                                                                    if (!HandleObservable<ThumbnailView>(parent, count))
                                                                                    {
                                                                                        if (!HandleList<byte[]>(parent, count))
                                                                                        {
                                                                                            if (!HandleObservable<byte[]>(parent, count))
                                                                                            {
                                                                                                if (!HandleEnumerable<byte[]>(parent, count))
                                                                                                {
                                                                                                }
                                                                                            }
                                                                                        }
                                                                                    }
                                                                                }
                                                                            }
                                                                        }
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            var res = _TypePropertyLookup.Get(parent.GetType(), (t) =>
            {
                var properties = t.GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic);
                var results = (from prop in properties
                               let r = prop.Name
                               let pt = prop.PropertyType
                               where prop.CanRead && !(r == "ImageBytes" || r == "Bitmap" || r == "ImageSource" || r == "Thumbnail" || r == "ImageInfo" || r == "TransformedBitmap") &&
                               (typeof(FileImageViewModel).IsAssignableFrom(pt) ||
                               typeof(FileImage).IsAssignableFrom(pt) ||
                               typeof(IFileImage).IsAssignableFrom(pt) ||
                               typeof(Bitmap).IsAssignableFrom(pt) ||
                               typeof(ThumbnailView).IsAssignableFrom(pt) ||
                               typeof(ImageSource).IsAssignableFrom(pt) ||
                               typeof(byte[]).IsAssignableFrom(pt) ||
                               typeof(IList<FileImageViewModel>).IsAssignableFrom(pt) ||
                               typeof(IList<ThumbnailView>).IsAssignableFrom(pt) ||
                               typeof(IList<FileImage>).IsAssignableFrom(pt) ||
                               typeof(IList<IFileImage>).IsAssignableFrom(pt) ||
                               typeof(IList<Bitmap>).IsAssignableFrom(pt) ||
                               typeof(IList<ImageSource>).IsAssignableFrom(pt) ||
                               typeof(IList<byte[]>).IsAssignableFrom(pt) ||
                               typeof(ObservableCollection<FileImageViewModel>).IsAssignableFrom(pt) ||
                               typeof(ObservableCollection<ThumbnailView>).IsAssignableFrom(pt) ||
                               typeof(ObservableCollection<FileImage>).IsAssignableFrom(pt) ||
                               typeof(ObservableCollection<IFileImage>).IsAssignableFrom(pt) ||
                               typeof(ObservableCollection<Bitmap>).IsAssignableFrom(pt) ||
                               typeof(ObservableCollection<ImageSource>).IsAssignableFrom(pt) ||
                               typeof(ObservableCollection<byte[]>).IsAssignableFrom(pt) ||
                               typeof(IEnumerable<FileImageViewModel>).IsAssignableFrom(pt) ||
                               typeof(IEnumerable<FileImage>).IsAssignableFrom(pt) ||
                               typeof(IEnumerable<ThumbnailView>).IsAssignableFrom(pt) ||
                               typeof(IEnumerable<IFileImage>).IsAssignableFrom(pt) ||
                               typeof(IEnumerable<Bitmap>).IsAssignableFrom(pt) ||
                               typeof(IEnumerable<ImageSource>).IsAssignableFrom(pt) ||
                               typeof(IEnumerable<byte[]>).IsAssignableFrom(pt))
                               select prop).ToList();

                return results;
            });

            for (int i = 0; i < res.Count; i++)
            {
                var r = res[i];
                ParameterInfo[] pis = r.GetIndexParameters();
                if (pis != null && pis.Length > 0)
                {
                    continue;
                }

                object o = r.GetValue(parent, null);
                if (o != null && count.Seen[o] == null)
                {
                    Crawl(o, count);
                }
            }
        }


        private CountClass CountObjects()
        {
            CountClass counts = new CountClass();
            CollectionViews.ForEach(o => Crawl(o._vm, counts));
            FileImageCollectionViewModels.ForEach(o => Crawl(o, counts));
            FileImageCollectionViewModels.ForEach(o => Crawl(o._fileImageCollection, counts));
            CollectionViews.ForEach(o => Crawl(o.UpdateTimer._collectionView.ThumbsHandler.ThumbnailViewsLast, counts));
            for (int n = 0; n < CollectionViews.Count; n++)
            {
                var collectionView = CollectionViews[n];
                if (collectionView.UpdateTimer._collectionView.ThumbsHandler.ThumbPreloader != null)
                {
                    Crawl(collectionView.UpdateTimer._collectionView.ThumbsHandler.ThumbPreloader._preloadQueue.AllItems.Select(pl => pl._item), counts);
                    Crawl(collectionView.UpdateTimer._collectionView.ThumbsHandler.ThumbPreloader._working.AllItems, counts);
                }
                Crawl(collectionView.ThumbsHandler._thumbsByFileName, counts);
            }
            if (_FullViewerHandler.Handler.BitmapPreloader != null)
            {
                Crawl(_FullViewerHandler.Handler.BitmapPreloader._preloadQueue.AllItems.Select(pl => pl._item), counts);
                Crawl(_FullViewerHandler.Handler.BitmapPreloader._working.AllItems, counts);
            }
            Crawl(_FullViewerHandler, counts);
            CollectionViews.ForEach(o => Crawl(o, counts));
            Crawl(RecentlyUsedFileImages.RecentlyUsedBitmaps.Lookup.AllItems.Select(nn => nn.Item), counts);
            Crawl(RecentlyUsedFileImages.RecentlyUsedImageSources.Lookup.AllItems.Select(nn => nn.Item), counts);
            Crawl(RecentlyUsedFileImages.RecentlyUsedFileBytes.Lookup.AllItems.Select(nn => nn.Item), counts);
            Crawl(RecentlyUsedFileImages.RecentlyUsedTransformedBitmaps.Lookup.AllItems.Select(nn => nn.Item), counts);
            CollectionViews.ForEach(o => Crawl(o._lastSelected, counts));
            CollectionViews.ForEach(o => Crawl(o._vm, counts));
            CollectionViews.ForEach(o => Crawl(o.FileImageCollectionViewModel, counts));
            for (int n = 0; n < CollectionViews.Count; n++)
            {
                var collectionView = CollectionViews[n];
                //if (collectionView.ScrollHandler != null)
                //{
                //    Crawl(collectionView.ScrollHandler._lastVisibleResults, counts);
                //}
            }
            if (LazyLoadingImageSource._lazyLoaderImageSource != null && LazyLoadingImageSource._lazyLoaderImageSource._loadQueue != null)
            {
                Crawl(LazyLoadingImageSource._lazyLoaderImageSource._loadQueue.AllItems.Select(pl => pl._item), counts);
            }
            if (LazyLoadingImageSource._lazyLoaderImageSource != null && LazyLoadingImageSource._lazyLoaderImageSource._working != null)
            {
                Crawl(LazyLoadingImageSource._lazyLoaderImageSource._working.AllItems.Select(pl => pl._item), counts);
            }
            CollectionViews.ForEach(o => Crawl(o.ThumbsHandler._thumbsByFileName.AllItems.Select(tv => tv.FileImageViewModel), counts));
            return counts;
        }
    }
}
